home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************
- * *
- * Convert() converts a string containing a math *
- * function in two variables, X and Y, to a postfix *
- * notation string with the numeric constants and *
- * functions converted to one byte symbols. If any *
- * syntax errors occur they will be posted in the global *
- * external variable SyntaxErr. Definitions are in *
- * syntxerr.h. *
- * *
- * Evaluate() will substitute the X and Y values passed *
- * to it and return the value of the function. *
- * *
- * This program may be freely used for non-profit *
- * purposes as long as the copyright notice remains *
- * in the code. *
- * *
- ***********************************************************
- * *
- * Copyright 1987 Randy C. Finch *
- * *
- **********************************************************/
-
- /*-------------- INCLUDES ----------------*/
-
- #include "common.h"
-
-
- /*---------------- DEFINES -----------------*/
-
- #define NUMSYM 128 /* Number of constants allowed in function */
- #define SYMBASE 128 /* Base value for constants symbols */
- #define STACKSIZE 256 /* Stack size */
- #define SIN 1 /* Symbol for sine */
- #define COS 2 /* Symbol for cosine */
- #define TAN 3 /* Symbol for tangent */
- #define ASIN 4 /* Symbol for arcsine */
- #define ACOS 5 /* Symbol for arccosine */
- #define ATAN 6 /* Symbol for arctangent */
- #define SINH 7 /* Symbol for hyperbolic sine */
- #define COSH 8 /* Symbol for hyperbolic cosine */
- #define TANH 9 /* Symbol for hyperbolic tangent */
- #define EXP 10 /* Symbol for exponential */
- #define SQRT 11 /* Symbol for square root */
- #define LN 12 /* Symbol for natural logarithm */
- #define LOG 13 /* Symbol for logarithn base 10 */
- #define NULL 0 /* Symbol for null */
- #define TRUE 1 /* Symbol for true condition */
- #define FALSE 0 /* Symbol for false condition */
-
-
- /*------------ EXTERNAL GLOBALS ------------*/
-
- unsigned char SyntaxErr;
-
-
- /*---------------- GLOBALS ----------------*/
-
- struct CharStack {
- unsigned char c[STACKSIZE];
- long top;
- };
-
- struct NumStack {
- double n[STACKSIZE];
- long top;
- };
-
- static struct CharStack cstack;
-
- static struct NumStack nstack;
-
- static double Constants[NUMSYM];
-
- static unsigned char CurConstant;
-
- static unsigned char NewExpr[256];
-
-
- /*---------------- FUNCTIONS ----------------*/
-
- static char CharInStr(s,c)
- unsigned char *s;
- unsigned char c;
- {
- while (*s != NULL) {
- if (*s == c) return TRUE;
- ++s;
- }
- return FALSE;
- } /* CharInStr */
-
-
- static void Deposit(num)
- double num;
- {
- Constants[CurConstant - SYMBASE] = num;
- } /* Deposit */
-
-
- static void Substitute(symb, ptr, len)
- unsigned char symb;
- unsigned char *ptr;
- unsigned long len;
- {
- *ptr = symb;
-
- if (len > 1) {
- do {
- ++ptr;
- *ptr = *(ptr + len - 1);
- } while (*ptr != NULL);
- }
- } /* Substitute */
-
-
- static void RemoveSpaces(str)
- unsigned char *str;
- {
- unsigned char *ptr;
-
- while (*str != NULL) {
- if (*str == ' ') {
- ptr = str;
- do {
- *ptr = *(ptr + 1);
- ++ptr;
- } while ( *(ptr - 1) != NULL);
-
- --str;
- }
-
- ++str;
- }
- } /* RemoveSpaces */
-
-
- static void AddZero(ptr)
- char *ptr;
- {
- unsigned long len;
- char *i;
-
- len = strlen(ptr);
-
- for (i=ptr+len+1; i>ptr; --i)
- *i = *(i - 1);
-
- *ptr = '0';
- } /* AddZero */
-
-
- static unsigned char CPop()
- {
- if (cstack.top == 0) return 0;
- else {
- --cstack.top;
- return cstack.c[cstack.top + 1];
- }
- } /* CPop */
-
-
- static char CPush(c)
- unsigned char c;
- {
- if (cstack.top == STACKSIZE) return FALSE;
- else {
- ++cstack.top;
- cstack.c[cstack.top] = c;
- return TRUE;
- }
- } /* CPush */
-
-
- static unsigned char CTopOfStack()
- {
- return cstack.c[cstack.top];
- } /* CTopOfStack */
-
-
- static double NPop()
- {
- --nstack.top;
- return nstack.n[nstack.top + 1];
- } /* NPop */
-
-
- static void NPush(n)
- double n;
- {
- ++nstack.top;
- nstack.n[nstack.top] = n;
- } /* NPush */
-
-
- static char IsFunction(c)
- unsigned char c;
- {
- if ( (c >= SIN) && (c <= LOG) )
- return TRUE;
- else
- return FALSE;
- } /* IsFunction */
-
-
- static char IsSymbol(c)
- unsigned char c;
- {
- if ((c >= SYMBASE) && (c < SYMBASE+NUMSYM))
- return TRUE;
- else
- return FALSE;
- } /* IsSymbol */
-
-
- static char Precedence(c1,c2)
- unsigned char c1,c2;
- {
- if ( (CharInStr("+-*/",c1)) && (c2 == '^') )
- return FALSE;
-
- else if ( (CharInStr("+-",c1)) && (CharInStr("*/",c2)) )
- return FALSE;
-
- else if ( ((c1 == '(') && (c2 != ')')) || (c2 == '(') )
- return FALSE;
-
- else if ( (CharInStr("+-*/^",c1)) && (IsFunction(c2)) )
- return FALSE;
-
- else
- return TRUE;
- } /* Precedence */
-
-
- static unsigned char *CheckSyntax(str)
- unsigned char *str;
- {
- int numLP = 0,
- numRP = 0;
-
- if ( (CharInStr("/*^E)",*str)) && (strncmp(str,"EXP",3) != 0) ) {
- if (CharInStr("/*^",*str)) {
- SyntaxErr = MISPLACEDOP;
- return str;
- }
- else if (*str == 'E') {
- SyntaxErr = ILLEGALEXP;
- return str;
- }
- else {
- SyntaxErr = MISSINGLP;
- return str;
- }
- } /* if */
-
- for (;;) { /* forever */
-
- if (*str == '(') {
- ++numLP;
- ++str;
- if ( (CharInStr("*/^E",*str)) && (strncmp(str,"EXP",3) != 0) ) {
- if (*str == 'E') {
- SyntaxErr = ILLEGALEXP;
- return str;
- }
- else {
- SyntaxErr = MISPLACEDOP;
- return str;
- }
- } /* if */
- if ( (*str == ')') || (*str == NULL) ) {
- SyntaxErr = MISSINGPARM;
- return str;
- }
- } /* if */
-
- else if (*str == ')') {
- ++numRP;
- ++str;
- if (numRP > numLP) {
- SyntaxErr = MISSINGLP;
- return (str-1);
- }
- else if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
- SyntaxErr = MISSINGOP;
- return str;
- }
- } /* else if */
-
- else if ( (isdigit(*str)) || (*str == '.') ) {
- char ExitFlag = FALSE,
- OneDecimal = FALSE,
- OneE = FALSE;
-
- if (*str == '.') OneDecimal = TRUE;
-
- ++str;
-
- if ( (OneDecimal == TRUE) && (!isdigit(*str)) ) {
- SyntaxErr = LONEDECIMAL;
- return (str - 1);
- }
-
- while ( ( (isdigit(*str)) || (CharInStr(".E)-+",*str))
- || (*str == NULL) ) && !ExitFlag ) {
-
- if (*str == '.') {
- ++str;
- if (OneE) {
- SyntaxErr = ILLEGALEXP;
- return (str-1);
- }
- else if (OneDecimal) {
- SyntaxErr = EXTRADECIMAL;
- return (str-1);
- }
- else if (strncmp(str,"EXP",3) == 0) {
- SyntaxErr = MISSINGOP;
- return str;
- }
- else if ( (!CharInStr("+-*/^E)",*str)) && (!isdigit(*str)) ) {
- SyntaxErr = ILLEGALCHAR;
- return str;
- }
- else {
- OneDecimal = TRUE;
- }
- } /* if */
-
- else if (*str == 'E') {
- ++str;
- if (OneE) {
- SyntaxErr = EXTRAE;
- return (str-1);
- }
- else if ( (!CharInStr("+-",*str)) && (!isdigit(*str)) ) {
- SyntaxErr = ILLEGALEXP;
- return str;
- }
- else {
- OneE = TRUE;
- }
- } /* else if */
-
- else if (CharInStr("+-",*str)) {
- if ( *(str-1) == 'E' )
- ++str;
- else if ( !OneE || (OneE && isdigit(*(str-1))) )
- ExitFlag = TRUE;
- else {
- SyntaxErr = MISPLACEDOP;
- return str;
- }
- } /* else if */
-
- else if ( (*str == ')') || (*str == NULL) ) {
- if (CharInStr("+-E",*(str-1))) {
- SyntaxErr = ILLEGALEXP;
- return str;
- }
- else {
- ExitFlag = TRUE;
- }
- } /* else if */
-
- else {
- ++str;
- } /* else */
-
- } /* while */
-
- if( !CharInStr("+-*/)", *str) && (*str != NULL) ) {
- SyntaxErr = MISSINGOP;
- return str;
- }
-
- } /* else if */
-
- else if (CharInStr("+-*/^",*str)) {
- ++str;
- if ( (CharInStr(")E+-*/^",*str)) || (*str == NULL) ) {
- if (strncmp(str,"EXP",3) != 0) {
- SyntaxErr = MISPLACEDOP;
- return (str-1);
- }
- }
- } /* else if */
-
- else if (CharInStr("XY",*str)) {
- ++str;
- if ( (!CharInStr(")+-*/^",*str)) && (*str != NULL) ) {
- SyntaxErr = MISSINGOPRP;
- return str;
- }
- } /* else if */
-
- else if (isupper(*str)) {
- if (strncmp(str,"LN",2) == 0) str += 2;
- else if (strncmp(str,"SINH",4) == 0) str += 4;
- else if (strncmp(str,"COSH",4) == 0) str += 4;
- else if (strncmp(str,"TANH",4) == 0) str += 4;
- else if (strncmp(str,"SIN",3) == 0) str += 3;
- else if (strncmp(str,"COS",3) == 0) str += 3;
- else if (strncmp(str,"TAN",3) == 0) str += 3;
- else if (strncmp(str,"EXP",3) == 0) str += 3;
- else if (strncmp(str,"LOG",3) == 0) str += 3;
- else if (strncmp(str,"SQRT",4) == 0) str += 4;
- else if (strncmp(str,"ASIN",4) == 0) str += 4;
- else if (strncmp(str,"ACOS",4) == 0) str += 4;
- else if (strncmp(str,"ATAN",4) == 0) str += 4;
- else {
- SyntaxErr = ILLEGALFUNC;
- return str;
- }
-
- if (*str != '(') {
- SyntaxErr = MISSINGLP;
- return str;
- }
- } /* else if */
-
- else if (*str == NULL) {
- if (numLP < numRP) {
- SyntaxErr = MISSINGLP;
- return str;
- }
- else if (numLP > numRP) {
- SyntaxErr = MISSINGRP;
- return str;
- }
- else {
- SyntaxErr = FALSE;
- return 0L;
- }
- } /* else if */
-
- else {
- SyntaxErr = ILLEGALCHAR;
- return str;
- }
-
- } /* for */
-
- } /* CheckSyntax */
-
-
- static char ConvertConstants(str)
- unsigned char *str;
- {
- unsigned char *ptr;
-
- ptr = str;
- if ( CharInStr("+-",*ptr) ) {
- AddZero(str);
- ptr += 2;
- }
-
- while ( *ptr != NULL ) {
- if ( (CharInStr("+-",*ptr)) && (*(ptr-1) == '(') )
- AddZero(ptr);
-
- ++ptr;
-
- } /* while */
-
- #if DEBUG
- printf("\nAddZero: %s\n", str);
- #endif
-
- { /* begin block */
- unsigned long j;
- unsigned char numstr[80];
- double number;
-
- ptr = str;
-
- CurConstant = SYMBASE;
-
- while ( *ptr != NULL) {
- if ( (*ptr == '.') || (isdigit(*ptr)) ) {
- unsigned long lennum = 1;
-
- while ( (CharInStr(".E-+",*(ptr+lennum))) || (isdigit(*(ptr+lennum))) ) {
- if( (CharInStr("-+",*(ptr+lennum))) && (*(ptr+lennum-1) != 'E') )
- break;
- ++lennum;
- }
-
- for (j=0; j<lennum; ++j)
- *(numstr+j) = *(ptr+j);
-
- *(numstr+j) = NULL;
-
- number = atof(numstr);
- Deposit(number);
- Substitute(CurConstant, ptr, lennum);
-
- ++CurConstant;
- if (CurConstant >= SYMBASE+NUMSYM) {
- SyntaxErr = TOOMANYCONST;
- return FALSE;
- }
-
- } /* if */
-
- ++ptr;
-
- } /* while */
-
- } /* end block */
-
- return TRUE;
-
- } /* ConvertConstants */
-
-
- static void ConvertFunctions(str)
- unsigned char *str;
- {
- while ( *str != NULL ) {
- if ( (isupper(*str)) && (!CharInStr("XY",*str)) ) {
-
- if (strncmp(str,"LN",2) == 0) Substitute(LN,str,2L);
- else if (strncmp(str,"SINH",4) == 0) Substitute(SINH,str,4L);
- else if (strncmp(str,"COSH",4) == 0) Substitute(COSH,str,4L);
- else if (strncmp(str,"TANH",4) == 0) Substitute(TANH,str,4L);
- else if (strncmp(str,"SIN",3) == 0) Substitute(SIN,str,3L);
- else if (strncmp(str,"COS",3) == 0) Substitute(COS,str,3L);
- else if (strncmp(str,"TAN",3) == 0) Substitute(TAN,str,3L);
- else if (strncmp(str,"EXP",3) == 0) Substitute(EXP,str,3L);
- else if (strncmp(str,"LOG",3) == 0) Substitute(LOG,str,3L);
- else if (strncmp(str,"SQRT",4) == 0) Substitute(SQRT,str,4L);
- else if (strncmp(str,"ASIN",4) == 0) Substitute(ASIN,str,4L);
- else if (strncmp(str,"ACOS",4) == 0) Substitute(ACOS,str,4L);
- else if (strncmp(str,"ATAN",4) == 0) Substitute(ATAN,str,4L);
-
- } /* if */
-
- ++str;
-
- } /* while */
-
- } /* ConvertFunctions */
-
-
- static char InfixToPostfix(str)
- unsigned char *str;
- {
- unsigned long i1=0, i2=0;
- unsigned char NextChar, TopSymbol;
-
- cstack.top = 0; /* Initialize stack */
- NewExpr[0] = NULL; /* Initialize expression */
-
- while ( *(str+i1) != NULL ) {
-
- NextChar = *(str+i1);
-
- if ( (IsSymbol(NextChar)) || (NextChar == 'X') || (NextChar == 'Y') ) {
- NewExpr[i2] = NextChar;
- ++i2;
- }
- else {
- for (;;) { /* Forever */
-
- if ( (cstack.top == 0) || (!Precedence(CTopOfStack(),NextChar)) )
- break;
-
- if ((TopSymbol = CPop()) == 0) {
- SyntaxErr = STACKUNDERFLOW;
- return FALSE;
- }
-
- if (cstack.top != 0) {
- if ( (IsFunction( CTopOfStack() )) && (NextChar == ')') ) {
- TopSymbol = CPop();
- NewExpr[i2] = TopSymbol;
- ++i2;
- break;
- } /* if */
- } /* if */
-
- if ( (TopSymbol == '(') && (NextChar == ')') )
- break;
-
- if (TopSymbol != '(') {
- NewExpr[i2] = TopSymbol;
- ++i2;
- }
-
- } /* for */
-
- if (NextChar != ')') {
- if (CPush(NextChar) == FALSE) {
- SyntaxErr = STACKOVERFLOW;
- return FALSE;
- }
- }
-
- } /* if */
-
- ++i1;
-
- } /* while */
-
- while (cstack.top != 0) {
- TopSymbol = CPop();
- if (TopSymbol != '(') {
- NewExpr[i2] = TopSymbol;
- ++i2;
- }
- }
-
- NewExpr[i2] = NULL;
-
- return TRUE;
-
- } /* InfixToPostfix */
-
-
- static double Calculate(s,n2,n1)
- unsigned char s;
- double n1,n2;
- {
- switch (s) {
- case '+':
- return (n1 + n2);
- case '-':
- return (n1 - n2);
- case '*':
- return (n1 * n2);
- case '/':
- return (n1 / n2);
- case '^':
- return ( exp(n2*log(n1)) );
- case SIN:
- return ( sin(n2) );
- case COS:
- return ( cos(n2) );
- case TAN:
- return ( tan(n2) );
- case EXP:
- return ( exp(n2) );
- case SQRT:
- return ( sqrt(n2) );
- case LN:
- return ( log(n2) );
- case LOG:
- return ( log10(n2) );
- case ASIN:
- return ( asin(n2) );
- case ACOS:
- return ( acos(n2) );
- case ATAN:
- return ( atan(n2) );
- case SINH:
- return ( sinh(n2) );
- case COSH:
- return ( cosh(n2) );
- case TANH:
- return ( tanh(n2) );
-
- } /* switch */
-
- } /* Calculate */
-
-
- unsigned char *Convert(FunctionString)
- unsigned char *FunctionString;
- {
- unsigned char fstr[512];
- unsigned char *ptr;
-
- SyntaxErr = FALSE;
-
- RemoveSpaces(FunctionString);
-
- #if DEBUG
- printf("\nRemoveSpaces: %s\n", FunctionString);
- #endif
-
- strupr(FunctionString);
-
- #if DEBUG
- printf("\nstrupr: %s\n", FunctionString);
- #endif
-
- if ((ptr = CheckSyntax(FunctionString)) != 0) return ptr;
-
- strcpy(fstr,FunctionString);
-
- #if DEBUG
- printf("\nCheckSyntax: %s\n", fstr);
- #endif
-
- if (!ConvertConstants(fstr)) return fstr;
-
- #if DEBUG
- printf("\nConvertConstants: ");
-
- for(ptr = fstr; *ptr != NULL; ++ptr)
- printf("%d ", *ptr);
-
- printf("\n");
- #endif
-
- ConvertFunctions(fstr);
-
- #if DEBUG
- printf("\nConvertFunctions: ");
-
- for(ptr = fstr; *ptr != NULL; ++ptr)
- printf("%d ", *ptr);
-
- printf("\n");
- #endif
-
- if (!InfixToPostfix(fstr)) return fstr;
-
- #if DEBUG
- {
- unsigned char *ptr;
-
- printf("\nInfixToPostfix: ");
-
- for(ptr = NewExpr; *ptr != NULL; ++ptr)
- printf("%d ", *ptr);
-
- printf("\n");
- }
- #endif
-
- return NewExpr;
-
- } /* Convert */
-
-
- double Evaluate(x,y)
- double x, y;
- {
- unsigned char symbol;
- long i = 0;
-
- nstack.top = 0; /* Initialize stack */
-
- while (NewExpr[i] != NULL) {
- symbol = NewExpr[i];
-
- if (symbol == 'X')
- NPush(x);
-
- else if (symbol == 'Y')
- NPush(y);
-
- else if (IsSymbol(symbol)) {
- NPush( Constants[symbol-SYMBASE] );
- }
-
- else if (IsFunction(symbol)) {
- NPush( Calculate(symbol, NPop(), 0.0) );
- }
-
- else {
- NPush( Calculate(symbol, NPop(), NPop()) );
- }
-
- ++i;
-
- } /* while */
-
- return NPop();
-
- } /* Evaluate */
-